package com.nchu.commondevelopmentframework.common.storage.impl;

import com.nchu.commondevelopmentframework.common.exception.file.FileNotExistException;
import com.nchu.commondevelopmentframework.common.storage.StorageStrategy;
import com.nchu.commondevelopmentframework.common.storage.config.LocalProperties;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @className: LocalStorageImpl
 * @description: 本地存储实现类
 * @author: Li Chuanwei
 * @date: 2024/01/22 23:04
 * @Company: Copyright [日期] by [作者或个人]
 **/
@Component
@Slf4j
public class LocalStorageImpl implements StorageStrategy {
    @Autowired
    private LocalProperties localProperties;

    private static final String DEFAULT_BASE_PATH = "";
    /**
     * 创建文件夹或目录
     *
     * @param directoryName 目录路径
     * @return true:成功 false:失败
     */
    @Override
    public boolean createDirectory(String directoryName) {
        String basePath = (localProperties.getBasePath() != null) ? localProperties.getBasePath() : DEFAULT_BASE_PATH;
        try {
            String fullPath = basePath + File.separator + directoryName;

            //判断是否以/结尾
            if(!fullPath.endsWith("/")){
                fullPath += "/";
            }

            // Create directory if it doesn't exist
            File directory = new File(fullPath);
            if (!directory.exists()) {
                boolean created = directory.mkdirs();
                if (!created) {
                    log.error("Failed to create directory: {}", fullPath);
                    return false;
                }
            }
            return true;
        } catch (Exception e) {
            log.error("创建文件夹或目录失败", e);
            return false;
        }
    }

    /**
     * 判断文件是否存在
     *
     * @param objectName 文件名（包括路径  eg:222/333.txt）
     * @return 存在返回true，不存在发生异常返回false
     */
    @Override
    public boolean objectExist(String objectName) {
        String basePath = (localProperties.getBasePath() != null) ? localProperties.getBasePath() : DEFAULT_BASE_PATH;
        String fullPath = basePath + File.separator + objectName;
        File file = new File(fullPath);
        return file.exists() && file.isFile();
    }

    /**
     * 判断文件夹是否存在【注意是文件夹而不是目录】
     *
     * @param folderName 文件夹名称（结尾为/）
     * @return 存在返回true，不存在发生异常返回false
     */
    @Override
    public boolean folderExist(String folderName) {
        String basePath = (localProperties.getBasePath() != null) ? localProperties.getBasePath() : DEFAULT_BASE_PATH;
        String fullPath = basePath + File.separator + folderName;
        File folder = new File(fullPath);
        return folder.exists() && folder.isDirectory();
    }

    /**
     * 文件上传
     *
     * @param multipartFile 待上传文件
     * @param folderName    目录
     * @param aimFileName   最终保存到存储中的文件名，不需要后缀
     * @return 返回上传成功后的文件的url
     */
    @Override
    public String uploadFileAndGetURL(MultipartFile multipartFile, String folderName, String aimFileName) {
        String basePath = (localProperties.getBasePath() != null) ? localProperties.getBasePath() : DEFAULT_BASE_PATH;

        // Ensure the directory exists
        createDirectory(folderName);

        // Generate unique filename if not provided
        if (!org.springframework.util.StringUtils.hasText(aimFileName)) {
            aimFileName = UUID.randomUUID().toString();
        }

        // Get the file extension
        String originalFilename = multipartFile.getOriginalFilename();
        if (originalFilename != null && originalFilename.lastIndexOf(".") != -1) {
            String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
            aimFileName += suffix;
        }

        // Full file path with name
        String filePath = basePath + File.separator + folderName + File.separator + aimFileName;

        try {
            multipartFile.transferTo(new File(filePath));
            return filePath;
        } catch (IOException e) {
            log.error("File upload failed", e);
        }
        return null;
    }

    /**
     * 上传文件【不指定文件夹】
     *
     * @param multipartFile 待上传文件
     * @param fileName      最终保存到存储中的文件名，不需要后缀
     * @return 返回上传成功后的文件的url
     */
    @Override
    public String uploadFileAndGetURL(MultipartFile multipartFile, String fileName) {
        return uploadFileAndGetURL(multipartFile, null, fileName);
    }

    /**
     * 上传文件【不指定文件夹,不指定目标文件名】
     *
     * @param multipartFile 待上传文件
     * @return 返回上传成功后的文件的url
     */
    @Override
    public String uploadFileAndGetURL(MultipartFile multipartFile) {
        return uploadFileAndGetURL(multipartFile, null, null);
    }

    /**
     * 拷贝文件
     *
     * @param destinationBucketName 目标bucket名称
     * @param destinationKey       目标文件名称
     * @param sourceKey            文件名称（包括目录）
     * @return 成功返回true，失败发生异常返回false
     */
    @Override
    public boolean copyObject(String destinationBucketName, String destinationKey, String sourceKey) {
        String basePath = (localProperties.getBasePath() != null) ? localProperties.getBasePath() : DEFAULT_BASE_PATH;

        // Local storage doesn't have a concept of buckets, so just copy the file within the local directory
        String sourcePath = basePath + File.separator + sourceKey;
        String destinationPath = basePath + File.separator + destinationKey;

        try {
            Files.copy(new File(sourcePath).toPath(), new File(destinationPath).toPath());
            return true;
        } catch (IOException e) {
            log.error("Copy failed", e);
            return false;
        }
    }

    /**
     * 文件下载
     *
     * @param fileName 文件名称
     * @param response response
     * @return 成功返回true，失败发生异常返回false
     */
    @Override
    public boolean getObject(String fileName, HttpServletResponse response) {
        String basePath = (localProperties.getBasePath() != null) ? localProperties.getBasePath() : DEFAULT_BASE_PATH;
        String filePath = basePath + File.separator + fileName;
        File file = new File(filePath);

        if (file.exists() && file.isFile()) {
            try {
                // 设置响应头
                response.setCharacterEncoding("utf-8");
                response.setContentType("application/octet-stream");
                response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));

                // 获取输出流
                OutputStream outputStream = response.getOutputStream();

                // 获取文件输入流
                FileInputStream inputStream = new FileInputStream(file);

                // 复制文件内容到输出流
                byte[] buffer = new byte[1024];
                int len;
                while ((len = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, len);
                }

                // 关闭输入流和输出流
                inputStream.close();
                outputStream.flush();
                outputStream.close();

                log.info("'{}'文件下载成功", fileName);
                return true;
            } catch (IOException e) {
                log.error("文件下载失败", e);
            }
        } else {
            throw new FileNotExistException(fileName);
        }
        return false;
    }


    /**
     * 获取指定路径下的所有文件对象
     *
     * @param keyPrefix 文件名称
     * @return 存储bucket内指定路径下文件对象信息
     */
    @Override
    public List<String> getBucketObjects(String keyPrefix) {
        String basePath = (localProperties.getBasePath() != null) ? localProperties.getBasePath() : DEFAULT_BASE_PATH;

        String directoryPath = basePath + File.separator + keyPrefix;
        File directory = new File(directoryPath);
        List<String> list = new ArrayList<>();

        // 递归遍历目录及其子目录
        listFiles(directory, keyPrefix, list);

        return list;
    }

    /**
     * 递归遍历目录及其子目录
     */
    private void listFiles(File directory, String relativePath, List<String> fileList) {
        if (directory.exists() && directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isFile()) {
                        String filePath = relativePath + File.separator + file.getName();
                        fileList.add(filePath.replace("\\", "/"));
                    } else if (file.isDirectory()) {
                        // 递归处理子目录
                        listFiles(file, relativePath + File.separator + file.getName(), fileList);
                    }
                }
            }
        }
    }

    /**
     * 删除文件
     *
     * @param fileName 文件名
     * @return 成功返回true，失败发生异常返回false
     */
    @Override
    public boolean removeObject(String fileName) {
        String basePath = (localProperties.getBasePath() != null) ? localProperties.getBasePath() : DEFAULT_BASE_PATH;

        String filePath = basePath + File.separator + fileName;
        File file = new File(filePath);

        if (file.exists() && file.isFile()) {
            boolean deleted = file.delete();
            if (!deleted) {
                log.error("Failed to delete file: {}", fileName);
                return false;
            }
        } else {
            throw new FileNotExistException(fileName);
        }
        return true;
    }
}
